package com.dove.authority.Async;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.dove.authority.entity.vo.PermissionVo;
import com.dove.authority.mapper.PermissionMapper;
import com.dove.authority.mapper.RoleMapper;
import com.dove.entity.GlobalException;
import com.dove.entity.MySimpleGrantedAuthority;
import com.dove.entity.Result;
import com.dove.entity.UserDetailsImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author run
 * @since 2021/3/20 21:48
 */
@Component
public class AuthorityAsync {

    @Autowired
    private PermissionMapper permissionMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Value("${spring.redis.content-key.user-details}")
    private String USER_DETAILS_KEY;

    @Autowired
    private RoleMapper roleMapper;

    @Async("asyncTaskExecutor")
    public void getAuthorityOfRole(Long roleId, CountDownLatch count, Lock lock, Set<MySimpleGrantedAuthority> set){
        List<String> permissions = permissionMapper.getPermissionNameOfRole(roleId);
        List<MySimpleGrantedAuthority> authorities = new ArrayList<>(permissions.size());
        permissions.forEach(permission -> authorities.add(new MySimpleGrantedAuthority(permission)));

        lock.lock();
        set.addAll(authorities);
        lock.unlock();

        count.countDown();
    }



    @Async("asyncTaskExecutor")
    public void updateAuthorityOfUser(Long userId, CountDownLatch count){

        //获取用户的角色id列表
        List<Long> roleIds = roleMapper.findRoleIdsOfUser(userId);
        Set<MySimpleGrantedAuthority> authorities = new HashSet<>();
        Lock lock = new ReentrantLock();
        CountDownLatch childCount = new CountDownLatch(roleIds.size());

        roleIds.forEach(roleId -> getAuthorityOfRole(roleId, count, lock, authorities));

        try {
            childCount.await(5, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            throw new GlobalException(Result.error("权限信息填充失败"));
        }

        UserDetailsImpl userDetails = (UserDetailsImpl) redisTemplate.opsForValue().get(USER_DETAILS_KEY + userId);

        //设置权限信息
        userDetails.setAuthorities(new ArrayList<>(authorities));

        redisTemplate.opsForValue().set(USER_DETAILS_KEY + userId, userDetails);

        count.countDown();
    }

    @Async("asyncTaskExecutor")
    public Future<String> addPermissionOfRole(List<Long> permissions, Long roleId){
        CountDownLatch count = new CountDownLatch(permissions.size());

        permissions.forEach(permissionId -> addPermissionOfRole(roleId, permissionId, count));

        try {
            count.await(5, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            throw new GlobalException(Result.error("添加权限信息错误"));
        }
        return new AsyncResult<>(null);
    }

    @Async("asyncTaskExecutor")
    public void addPermissionOfRole(Long roleId, Long permissionId, CountDownLatch count){
        permissionMapper.addPermissionOfRole(roleId, permissionId, IdWorker.getId());
        count.countDown();
    }

    @Async("asyncTaskExecutor")
    public Future<List<PermissionVo>> getAllPermission(){
        List<PermissionVo> rootPermission = permissionMapper.getRootPermission();

        CountDownLatch count = new CountDownLatch(rootPermission.size());

        rootPermission.forEach(permissionVo -> setChildPermission(permissionVo, count));

        try {
            count.await(5, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return new AsyncResult<>(rootPermission);

    }

    @Async("asyncTaskExecutor")
    public void setChildPermission(PermissionVo parent, CountDownLatch count){
        List<PermissionVo> childPermission = permissionMapper.getPermissionOfParent(parent.getId());
        parent.setChildPermission(childPermission);

        CountDownLatch childCount = new CountDownLatch(childPermission.size());

        childPermission.forEach(permissionVo -> setChildPermission(permissionVo, childCount));

        try {
            childCount.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        count.countDown();

    }

    @Async("asyncTaskExecutor")
    public Future<List<PermissionVo>> getAllPermission(Long roleId){
        List<PermissionVo> rootPermission = permissionMapper.getRootPermissionOfRole(roleId);

        CountDownLatch count = new CountDownLatch(rootPermission.size());

        rootPermission.forEach(permissionVo -> setChildPermission(permissionVo, count));

        try {
            count.await(5, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return new AsyncResult<>(rootPermission);
    }

}
